package main.java.maziacs.characters;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

import main.java.maziacs.Gem;
import main.java.maziacs.IBoard;
import main.java.maziacs.IGame;
import main.java.maziacs.ITile;
import main.java.maziacs.counters.Counter;
import main.java.maziacs.counters.Prisoner;
import main.java.maziacs.counters.Treasure;
import main.java.maziacs.rol.Rol;
import main.java.maziacs.rol.WithMaziacs;
import main.java.maziacs.rol.WithoutMaziacs;
import main.java.maziacs.squares.Square;
import main.java.maziacs.squares.White;


public class Hero extends Character implements IHero{

	private IBoard board;
	private Integer gems;
	private Position lastPosition;
	private Treasure tTreasure;
	/* (non-Javadoc)
	 * @see uml.elheroe#getBoard()
	 */
	public IBoard getBoard() {
		return board;
	}

	/* (non-Javadoc)
	 * @see uml.elheroe#setBoard(uml.IBoard)
	 */
	public void setBoard(IBoard board) {
		this.board = board;
	}

	public Hero(IBoard board, IGame game){
		tTreasure=null;
		this.board=board;
		setPosition(new Position(board.getStartTile(),board.getStartTile().getSquares()[1][1]));
		setSword(true);
		setEnergy(20);
		rol=new WithoutMaziacs(this);
		setTreasure(false);
		setScore(0);
		this.game=game;
		setNumberGems(game.getLevel().getNumberOfGems());
	}
	/**
	 * @uml.property  name="energy"
	 */
	private int energy;

	/* (non-Javadoc)
	 * @see uml.IHero#getEnergy()
	 */
	/* (non-Javadoc)
	 * @see uml.elheroe#getEnergy()
	 */
	public int getEnergy() {
		return energy;
	}

	/* (non-Javadoc)
	 * @see uml.IHero#setEnergy(int)
	 */
	/* (non-Javadoc)
	 * @see uml.elheroe#setEnergy(int)
	 */
	public void setEnergy(int energy) {
		this.energy = energy;
	}

	/**
	 * @uml.property  name="sword"
	 */
	private boolean sword;

		
	/* (non-Javadoc)
	 * @see uml.IHero#hasSword()
	 */
	/* (non-Javadoc)
	 * @see uml.elheroe#hasSword()
	 */
	public boolean hasSword(){
	
			return sword;
		 }

	/* (non-Javadoc)
	 * @see uml.IHero#setSword(boolean)
	 */
	/* (non-Javadoc)
	 * @see uml.elheroe#setSword(boolean)
	 */
	public void setSword(boolean sword) {
		this.sword = sword;
	}

	/**
	 * @uml.property  name="treasure"
	 */
	private boolean treasure;

		
	/* (non-Javadoc)
	 * @see uml.IHero#hasTreasure()
	 */
	/* (non-Javadoc)
	 * @see uml.elheroe#hasTreasure()
	 */
	public boolean hasTreasure(){
	
			return treasure;
		 }

	/* (non-Javadoc)
	 * @see uml.IHero#setTreasure(boolean)
	 */
	/* (non-Javadoc)
	 * @see uml.elheroe#setTreasure(boolean)
	 */
	public void setTreasure(boolean treasure) {
		this.treasure = treasure;
	}

	/**
	 * @uml.property  name="score"
	 */
	private int score;

	/* (non-Javadoc)
	 * @see uml.IHero#getScore()
	 */
	/* (non-Javadoc)
	 * @see uml.elheroe#getScore()
	 */
	public int getScore() {
		return score;
	}

	/* (non-Javadoc)
	 * @see uml.IHero#setScore(int)
	 */
	/* (non-Javadoc)
	 * @see uml.elheroe#setScore(int)
	 */
	public void setScore(int score) {
		this.score = score;
	}

		
		/* (non-Javadoc)
		 * @see uml.IHero#explore()
		 */
		/* (non-Javadoc)
		 * @see uml.elheroe#explore()
		 */
	public void explore(){
		Integer posI=this.getPosition().getSquare().getPositionI();
		Integer posJ=this.getPosition().getSquare().getPositionJ();
		List<Integer> l=new LinkedList<Integer>();
		ITile tile=this.getPosition().getTile();
		/*Dependiendo de la posicion en la que se encuentre el Heroe, se determina
		 * si se cumplen las condiciones para explorar:
		 * 1.- Se tiene linea de vision directa con una salida de la loseta
		 * 2.- En ese caso se comprueba si hay loseta adyacente por esa casilla
		 * Si se tiene linea de vision directa con varias salidas(lo que solo puede ocurrir
		 * en el caso de que nos encontremos en la casilla central, posI=1 y posJ=1), se explora
		 * una de las salidas al azar*/
		if(posI==0){
			l.add(posI+2);
			l.add(posJ);
			if(tile.getSquares()[posI+2][posJ] instanceof White && !tile.getAdjacentTiles().containsValue(l)){
				ITile t=board.takeOutTile();
				System.out.println("Vamos a colocar la nueva loseta en la posicion (" + 
						(posI+2) + ", " + (posJ) + 
						") de la loseta " + tile.getName() + "\n");
				game.getIntUsu().choosePutTile(tile, tile.getSquares()[posI+2][posJ],t);
				//game.getBoard().putMaziac(t);
			}
			l.remove(0);
			l.remove(0);
		}
		else if(posI==2){
			l.add(posI-2);
			l.add(posJ);
			if(tile.getSquares()[posI-2][posJ] instanceof White && !tile.getAdjacentTiles().containsValue(l)){
				ITile t=board.takeOutTile();
				System.out.println("Vamos a colocar la nueva loseta en la posicion (" + 
						(posI-2) + ", " + (posJ) + 
						") de la loseta " + tile.getName() + "\n");
				game.getIntUsu().choosePutTile(tile, tile.getSquares()[posI-2][posJ],t);
				//game.getBoard().putMaziac(t);
			}
			l.remove(0);
			l.remove(0);
		}
		else if(posI==1){
			if(posJ==0){
				l.add(posI);
				l.add(posJ+2);
				if(tile.getSquares()[posI][posJ+2] instanceof White && !tile.getAdjacentTiles().containsValue(l)){
					ITile t=board.takeOutTile();
					System.out.println("Vamos a colocar la nueva loseta en la posicion (" + 
							(posI) + ", " + (posJ+2) + 
							") de la loseta " + tile.getName() + "\n");
					game.getIntUsu().choosePutTile(tile, tile.getSquares()[posI][posJ+2], t);
					//game.getBoard().putMaziac(t);
				}
				l.remove(0);
				l.remove(0);
			}
			else if(posJ==2){
				l.add(posI);
				l.add(posJ-2);
				if(tile.getSquares()[posI][posJ-2] instanceof White && !tile.getAdjacentTiles().containsValue(l)){
					ITile t=board.takeOutTile();
					System.out.println("Vamos a colocar la nueva loseta en la posicion (" + 
							(posI) + ", " + (posJ-2) + 
							") de la loseta " + tile.getName() + "\n");
					game.getIntUsu().choosePutTile(tile, tile.getSquares()[posI][posJ-2], t);
					//game.getBoard().putMaziac(t);
				}
				l.remove(0);
				l.remove(0);
			}
			else if (posJ==1){
				List<Square> s=new LinkedList<Square>();
				s.add(tile.getSquares()[0][1]);
				s.add(tile.getSquares()[1][0]);
				s.add(tile.getSquares()[1][2]);
				s.add(tile.getSquares()[2][1]);
				Iterator<Square> it=s.iterator();
				while(it.hasNext()){
					Square sq=it.next();
					l.add(sq.getPositionI());
					l.add(sq.getPositionJ());
					if(!(sq instanceof White) || tile.getAdjacentTiles().containsValue(l))
						it.remove();
				}
//				l.remove(0);
//				l.remove(0);
				if(s.size()!=0){
					Random r=new Random();
					int x=r.nextInt(s.size());
					ITile t=board.takeOutTile();
					System.out.println("Vamos a colocar la nueva loseta en la posicion (" + 
							s.get(x).getPositionI() + ", " + s.get(x).getPositionJ() + 
							") de la loseta " + tile.getName() + "\n");
					game.getIntUsu().choosePutTile(tile, s.get(x), t);
					//game.getBoard().putMaziac(t);
				}
			}
		}
	}


		/**
		 * @uml.property  name="battle"
		 * @uml.associationEnd  multiplicity="(1 1)" inverse="hero:uml.Battle"
		 */
		private Battle battle;

		/* (non-Javadoc)
		 * @see uml.IHero#getBattle()
		 */
		/* (non-Javadoc)
		 * @see uml.elheroe#getBattle()
		 */
		public Battle getBattle() {
			return battle;
		}

		/* (non-Javadoc)
		 * @see uml.IHero#setBattle(uml.Battle)
		 */
		/* (non-Javadoc)
		 * @see uml.elheroe#setBattle(uml.Battle)
		 */
		public void setBattle(Battle battle) {
			this.battle = battle;
		}

		/**
		 * @uml.property  name="game"
		 * @uml.associationEnd  multiplicity="(1 1)" inverse="hero:uml.Game"
		 */
		private IGame game;

		/* (non-Javadoc)
		 * @see uml.IHero#getGame()
		 */
		/* (non-Javadoc)
		 * @see uml.elheroe#getGame()
		 */
		public IGame getGame() {
			return game;
		}

		/* (non-Javadoc)
		 * @see uml.IHero#setGame(uml.Game)
		 */
		/* (non-Javadoc)
		 * @see uml.elheroe#setGame(uml.IGame)
		 */
		public void setGame(IGame game) {
			this.game = game;
		}

		/**
		 * @uml.property  name="rol"
		 * @uml.associationEnd  multiplicity="(1 1)" inverse="hero:uml.Rol"
		 */
		private Rol rol;

		/* (non-Javadoc)
		 * @see uml.IHero#getRol()
		 */
		/* (non-Javadoc)
		 * @see uml.elheroe#getRol()
		 */
		public Rol getRol() {
			return rol;
		}

		/* (non-Javadoc)
		 * @see uml.IHero#setRol(uml.Rol)
		 */
		/* (non-Javadoc)
		 * @see uml.elheroe#setRol(uml.Rol)
		 */
		public void setRol(Rol rol) {
			this.rol = rol;
		}

		/**
		 * @uml.property  name="numberGems"
		 */
		private int numberGems;

		/* (non-Javadoc)
		 * @see uml.IHero#getNumberGems()
		 */
		/* (non-Javadoc)
		 * @see uml.elheroe#getNumberGems()
		 */
		public int getNumberGems() {
			return numberGems;
		}

		/* (non-Javadoc)
		 * @see uml.IHero#setNumberGems(int)
		 */
		/* (non-Javadoc)
		 * @see uml.elheroe#setNumberGems(int)
		 */
		public void setNumberGems(int numberGems) {
			this.numberGems = numberGems;
		}

		
		/* (non-Javadoc)
		 * @see uml.IHero#takeGem()
		 */
		/* (non-Javadoc)
		 * @see uml.elheroe#takeGem(uml.White)
		 */
		public void takeGem(White w){
			w.setGem(null);
		}

			
		/* (non-Javadoc)
		 * @see uml.IHero#putGem()
		 */
		/* (non-Javadoc)
		 * @see uml.elheroe#putGem()
		 */
		public void putGem(){
			/*Ponemos en la salida de la anterior loseta una gema*/
			ITile tile=getLastPosition().getTile();
			if(getGems()>0 && !getBoard().getPath().getPath().contains(tile)){
				for(ITile t: tile.getAdjacentTiles().keySet()){
					if(t.equals(getPosition().getTile())){
						List<Integer> l=tile.getAdjacentTiles().get(t);
						White w=(White)tile.getSquares()[l.get(0)][l.get(1)];
						w.setGem(new Gem(this.getGame()));
						this.getGame().setNumberOfGems(getGame().getNumberOfGems()-1);
						setGems(getGems()-1);
						getBoard().getPath().getPath().add(tile);
					}
				}
			}
		}
		private Prisoner lastPrisoner;
		private Square squarePath;
		
		/* (non-Javadoc)
		 * @see uml.elheroe#askPrisoner(uml.Counter)
		 */
		public void askPrisoner(Counter c){
			if(c instanceof Prisoner){
				Prisoner p=(Prisoner)c;
				lastPrisoner=p;
				setGems(2);
				setSquarePath(p.calculateDirection());
			}
		} 
		
		/* (non-Javadoc)
		 * @see uml.elheroe#move()
		 */
		public void move(){
			Boolean see=false;
			for(Maziacs m:board.getMaziacs().keySet()){
				if(m.seeHero(this)){
					see=true;
					break;
				}
			}
			if(see){
				setRol(new WithMaziacs(this));
				((WithMaziacs)getRol()).moveWithMaziacs();
			}
			else{
				setRol(new WithoutMaziacs(this));
				((WithoutMaziacs)getRol()).moveWithoutMaziacs();
			}
		}

		/* (non-Javadoc)
		 * @see uml.elheroe#setLastPosition(uml.Position)
		 */
		public void setLastPosition(Position lastPosition) {
			this.lastPosition = lastPosition;
		}

		/* (non-Javadoc)
		 * @see uml.elheroe#getLastPosition()
		 */
		public Position getLastPosition() {
			return lastPosition;
		}

		/* (non-Javadoc)
		 * @see uml.elheroe#setGems(java.lang.Integer)
		 */
		public void setGems(Integer gems) {
			this.gems = gems;
		}

		/* (non-Javadoc)
		 * @see uml.elheroe#getGems()
		 */
		public Integer getGems() {
			return gems;
		}

		/* (non-Javadoc)
		 * @see uml.elheroe#setLastPrisoner(uml.Prisoner)
		 */
		public void setLastPrisoner(Prisoner lastPrisoner) {
			this.lastPrisoner = lastPrisoner;
		}

		/* (non-Javadoc)
		 * @see uml.elheroe#getLastPrisoner()
		 */
		public Prisoner getLastPrisoner() {
			return lastPrisoner;
		}

		/* (non-Javadoc)
		 * @see uml.elheroe#setSquarePath(uml.Square)
		 */
		public void setSquarePath(Square squarePath) {
			this.squarePath = squarePath;
		}

		/* (non-Javadoc)
		 * @see uml.elheroe#getSquarePath()
		 */
		public Square getSquarePath() {
			return squarePath;
		}

		/* (non-Javadoc)
		 * @see uml.elheroe#setTTreasure(uml.Treasure)
		 */
		public void setTTreasure(Treasure tTreasure) {
			this.tTreasure = tTreasure;
		}

		/* (non-Javadoc)
		 * @see uml.elheroe#getTTreasure()
		 */
		public Treasure getTTreasure() {
			return tTreasure;
		}
// aki falta estos 2 motodos ?
		@Override
		public Integer getPrisoners() {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		public void setPrisoners(Integer prisoners) {
			// TODO Auto-generated method stub
			
		}
}
